package com.gw.booking.service;


import com.gw.booking.common.ApiException;
import com.gw.booking.common.Constant;
import com.gw.booking.common.MessageCode;
import com.gw.booking.common.Util;
import com.gw.booking.dto.PageDto;
import com.gw.booking.dto.backend.RoleAddDto;
import com.gw.booking.dto.backend.RoleDelDto;
import com.gw.booking.dto.backend.RoleListDtoOut;
import com.gw.booking.dto.backend.RoleUptDto;
import com.gw.booking.entity.LoginToken;
import com.gw.booking.entity.Role;
import com.gw.booking.entity.User;
import org.apache.commons.beanutils.BeanUtils;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class RoleService {

    @Autowired
    private SessionFactory sessionFactory;
    @Autowired
    private HqlService hqlService;

    /**
     * 取得用户信息
     */
    public User getUser(Session session, int userId) {
        return (User) session.get(User.class, userId);
    }

    /**
     * 新增角色
     */
    public void txAdd(LoginToken loginToken, RoleAddDto roleAddDto) throws IllegalAccessException,
            InvocationTargetException {
        Session session = sessionFactory.getCurrentSession();
        User user = getUser(session, loginToken.getUserId());
        //判断是否存在同名角色
        sureRoleColumnValue(session, "roleName", roleAddDto.getRoleName());
        Role role = new Role();
        BeanUtils.copyProperties(role, roleAddDto);
        role.setCreatedAt(new Timestamp(System.currentTimeMillis()));
        session.save(role);
        }

    /**
     * 删除角色
     */
    public void txDelete(LoginToken loginToken, RoleDelDto roleDelDto) {
        Session session = sessionFactory.getCurrentSession();
        Role role = getRole(session, roleDelDto.getId());
        // 该角色下存在用户，无法删除
        assertNoUser(session, roleDelDto.getId());
        // 若角色不存在或者该用户已删除
        if (role == null) {
            throw new ApiException(MessageCode.CODE_NO_ROLE);
        }
        session.delete(role);
         }

    /**
     * 获取角色列表
     */
    public PageDto<RoleListDtoOut> txGetRoleList(LoginToken loginToken
            , int page, int size) throws IllegalAccessException, InvocationTargetException,
            InstantiationException, NoSuchMethodException {
        Session session = sessionFactory.getCurrentSession();
        Map<String, Object> params = new HashMap<>();

        long total = (Long)session.createQuery(hqlService.getSqlCount("role.list", params, false))
                .setProperties(params).uniqueResult();
        List<Object> items = session.createQuery(hqlService.getSql("role.list", params)).setProperties(params).list();

        return new PageDto<RoleListDtoOut>(page, size, total, Util.convertBeanList(items, RoleListDtoOut.class));
    }

    /**
     * 编辑角色
     */
    public void txUpdate(LoginToken loginToken, RoleUptDto roleUptDto) {
        Session session = sessionFactory.getCurrentSession();
        Role role = getRole(session, roleUptDto.getId());
        User user = getUser(session, loginToken.getUserId());
        // 若该角色不存在或者该用户已被删除
        if (role == null) {
            throw new ApiException(MessageCode.CODE_NO_ROLE);
        }
        // 管理员角色不能修改
        if (role.getId() == Constant.ROLE_ID_ADMIN) {
            throw new ApiException(MessageCode.CODE_NO_PRIVILEGE);
        }
        role.setPrivilegeIds(roleUptDto.getPrivilegeIds());
        role.setRoleInfo(roleUptDto.getRoleInfo());
        role.setRoleName(roleUptDto.getRoleName());
        role.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
        session.update(role);
        session.flush();
        }

    /**
     * 确认没有指定角色的用户
     */
    public void assertNoUser(Session session, Integer roleId) {
        StringBuffer hqlCondition = new StringBuffer();
        hqlCondition.append(" from User ");
        hqlCondition.append(" where roleId = :roleId ");
        Query query = session.createQuery(hqlCondition.toString()).setParameter("roleId", roleId);
        List list = query.list();
        if (list.size() != 0) {
            throw new ApiException(MessageCode.CODE_ROLEDELETE_ERROR);
        }
    }

    /**
     * 确认角色信息
     */
    public Role assertRole(Session session, Integer roleId) {
        Role role = getRole(session, roleId);

        if (role == null) {
            throw new ApiException(MessageCode.CODE_NO_ROLE);
        }

        return role;
    }

    /**
     * 获取角色信息
     */
    public Role getRole(Session session, int roleId) {
        return (Role) session.get(Role.class, roleId);
    }

    /**
     * 根据角色名取得角色
     *
     * @param session
     * @param roleName
     * @return
     */
    public Role getRoleByName(Session session, String roleName) {
        return (Role) session.createCriteria(Role.class).add(Restrictions.eq("roleName", roleName)).uniqueResult();
    }

    /**
     * 取得角色名称
     */
    public String getRoleName(Session session, Integer roleId) {
        Role role = getRole(session, roleId);

        if (role == null) {
            return null;
        }

        return role.getRoleName();
    }

    /**
     * 确认某字段值【角色名称:roleName】是否已存在
     */
    public void sureRoleColumnValue(Session session, String columnName, String columnValue) {
        StringBuffer hqlCondition = new StringBuffer();
        hqlCondition.append(" from Role ");
        if ("roleName".equals(columnName)) {
            hqlCondition.append(" where roleName = :value ");

            Query query = session.createQuery(hqlCondition.toString()).setParameter("value", columnValue);
            List list = query.list();
            if (list.size() != 0) {
                throw new ApiException(MessageCode.CODE_ROLE_EXIST);
            }
        }
    }

  /**
   * 获取角色详情
   * @param loginToken
   * @param id
   * @return
   */
    public Role getDetail(LoginToken loginToken, Integer id) {
        Session session = sessionFactory.getCurrentSession();
        Role role = (Role) session.get(Role.class, id);
        return role;
    }
}
